home *** CD-ROM | disk | FTP | other *** search
/ The Very Best of Atari Inside / The Very Best of Atari Inside 1.iso / sharew / musik / bytes / midipbck.lst < prev    next >
Encoding:
File List  |  1989-04-05  |  11.2 KB  |  269 lines

  1. '
  2. ' '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  3. '  Playback-Version des Programms, zur Wiedergabe von MIDI-Standard-Dateien
  4. '  (ohne Taktanzeige usf. - dafür deutlich besseres Timing)
  5. '  geschrieben in GFA-BASIC 3.5E D, (C)1993 Stephan M. Sprenger
  6. '  PROSONIQ PRODUCTS SOFTWARE, Badenwerkstraße 9, 76137 Karlsruhe
  7. ' .............................................................................
  8. '
  9. '
  10. $I+             ! Compiler-Option: Interrupts initialisieren
  11. $P>             ! Compiler-Option: GFA-Konvention für Procedures
  12. '
  13. mtc!=FALSE      ! Synchronisation: FALSE=intern, TRUE=MIDI Clock
  14. tempo=0.01      ! Tempo:  Aufzeichnungs- und Abspielgeschwindigkeit
  15. '
  16. @init           ! Programm initialisieren
  17. @standby        ! Hauptschleife des Programms
  18. '
  19. ' Unter-Routinen zum Programm
  20. '
  21. PROCEDURE init
  22.   OPENW 0                               ! Bildschirm und Fenster...
  23.   DEFMOUSE 0
  24.   TITLEW #1," SEQUENCER - Playback-Only Version "
  25.   INFOW #1," "
  26.   OPENW #1,20,150,600,100,0
  27.   CLS
  28.   dm=FRE(0)/15
  29.   DIM dat$(dm)                          ! Feld für MIDI-Daten
  30.   DIM time%(dm)                         ! Feld für Absolutzeit
  31.   DIM d_len&(300)
  32.   OPEN "O",#99,"MID:"                   ! MIDI-Schnittstelle öffnen
  33. RETURN
  34. '
  35. PROCEDURE standby
  36.   DO
  37.     INFOW #1," Status: Stand-By     "+fn$
  38.     PRINT AT(28,2);"NO BAR COUNT DISPLAY"
  39.     key$=CHR$(INP(2))
  40.     IF key$="0"
  41.       INFOW #1," Status: Playback ... "+fn$
  42.       @playback
  43.     ELSE IF key$=CHR$(27)
  44.       @ende
  45.     ELSE IF key$="l" OR key$="L"
  46.       INFOW #1," Status: Loading MIDI Standard File ... "+fn$
  47.       @convert_mid(1,0)
  48.     ELSE IF INKEY$=CHR$(13)
  49.       @all_notes_off
  50.     ELSE
  51.       CLR key$
  52.     ENDIF
  53.   LOOP
  54. RETURN
  55. '
  56. PROCEDURE playback
  57.   tm=0
  58.   c%=1
  59.   VOID FRE(0)
  60.   dummy$=INPMID$                        ! MIDI-In-Puffer leeren ...
  61.   HIDEM
  62.   DO                                    ! Wiedergabe-Schleife
  63.     IF INP?(3)
  64.       in|=INP(3)
  65.     ELSE
  66.       in|=0
  67.     ENDIF
  68.     IF in|=248 AND mtc!=TRUE            ! MIDI-Clock?
  69.       INC tm                            ! Dann Uhr +1
  70.     ENDIF
  71.     IF mtc!=FALSE                       ! Interne Synchronisation?
  72.       DELAY tempo                       ! Dann Uhr nach Pause +1
  73.       INC tm
  74.     ENDIF
  75.     IF time%(c%)<=tm                    ! nächstes Event schon dran?
  76.       PRINT #99,dat$(c%);               ! Ja, dann ausgeben
  77.       INC c%
  78.     ENDIF
  79.     EXIT IF c%=>dm-1 OR c%=>last% OR INKEY$=CHR$(13)
  80.   LOOP
  81.   SHOWM
  82.   @all_notes_off                        ! Nach Beendigung alle Noten aus.
  83. RETURN
  84. '
  85. PROCEDURE ende
  86.   CLOSEW 1
  87.   CLOSEW 0
  88.   CLOSE
  89.   EDIT
  90. RETURN
  91. '
  92. PROCEDURE convert_mid(abs_rel|,save_load|)
  93.   '
  94.   ' speichert/lädt Daten als MIDI Standard File:
  95.   ' MIDI-Events in dat$(), Zeit als Clicks in time%()
  96.   '
  97.   ' Wenn Sie abs_rel| auf 1 setzen, erwartet die Routine in time%() die
  98.   ' Zeitangabe als Absolutzeit (also als Zeit seit Spuranfang); ist
  99.   ' abs_rel| Null, dann erwartet die Routine in time%() die seit dem
  100.   ' vorhergehenden Event verstrichene Zeit.
  101.   '
  102.   ' In dat$() befinden sich die zu speichernden MIDI-Events; diese müssen
  103.   ' pro Eintrag vollständig sein (ein Note-On liegt hier z.B. als
  104.   ' dat$(2)=CHR$(144)+CHR$(60)+CHR$(64) vor).
  105.   '
  106.   ' Wenn save_load|=1 ist wird gespeichert, bei save_load|=0 wird geladen
  107.   '
  108.   @convert_init                         ! Konvertierungsroutine einrichten
  109.   dummy$=INKEY$
  110.   FILESELECT "A:\*.MID","MIDIFILE.MID",fn$
  111.   DEFMOUSE 2
  112.   IF fn$="" OR fn$="\"
  113.     GOTO cancel
  114.   ENDIF
  115.   IF save_load|=1
  116.     OPEN "O",#1,fn$
  117.     PRINT #1,"MThd";                      ! **** Header-Block-Kennung ****
  118.     PRINT #1,MKL$(6);                     ! Länge des Headers
  119.     PRINT #1,MKI$(0);                     ! File Format (0)
  120.     PRINT #1,MKI$(1);                     ! Anzahl der Spuren
  121.     PRINT #1,MKI$(&H18);                  ! 24 Clicks pro Viertelnote (MIDI Clock)
  122.     PRINT #1,"MTrk";                      ! ***** Spur-Block-Kennung *****
  123.     PRINT #1,MKL$(0);                     ! Platzhalter für Blocklänge
  124.     PRINT #1,CHR$(0);                     ! Delta-Time des ersten Events
  125.     PRINT #1,CHR$(&HFF);                  ! Meta-Event: Spurname
  126.     PRINT #1,MKI$(&H108);                 ! (01=Text, 08=Textlänge)
  127.     PRINT #1,"MIDIFILE";                  ! Spurname
  128.     c%=0
  129.     DO
  130.       INC c%
  131.       VOID FRE(0)
  132.       r%=V:r$
  133.       IF abs_rel|=1                         ! time%() enthält Absolutzeit
  134.         LPOKE r%+6,(time%(c%)-time%(c%-1))  ! Zeit zwischen zwei Events
  135.       ELSE
  136.         LPOKE r%+6,time%(c%)                ! time%() enthält Delta-Time
  137.       ENDIF
  138.       POKE r%+2,1                           ! Opcode: 1=DEZ-->VLN, 0=VLN-->DEZ
  139.       d0=C:r%()                             ! VLN-Routine aufrufen
  140.       FOR b|=0 TO 3                         ! Bytes in Datei schreiben...
  141.         IF PEEK(r%+6+b|)<>0
  142.           PRINT #1,CHR$(PEEK(r%+6+b|));
  143.         ENDIF
  144.       NEXT b|
  145.       PRINT #1,dat$(c%);                    ! MIDI-Daten in Datei ausgeben
  146.       EXIT IF c%=last%                      ! Abbrechen wenn Spurende
  147.     LOOP
  148.     PRINT #1,CHR$(0);                       ! Delta-time% zum Spurende
  149.     PRINT #1,CHR$(&HFF);MKI$(&H2F00);       ! Meta-Event: Spurende
  150.     CLOSE #1
  151.     OPEN "U",#1,fn$                         ! Datei nochmals öffnen
  152.     l%=LOF(#1)                              ! Länge ermitteln
  153.     SEEK #1,18                              ! Byte #18 anfahren
  154.     PRINT #1,MKL$(l%-18);                   ! Spurlänge eintragen
  155.   ELSE
  156.     c%=0                                   ! Zähler für Feldindex
  157.     z%=0                                   ! Zähler für Absolutzeit
  158.     b%=0                                   ! Zähler für gelesene Bytes
  159.     evt$=""
  160.     OPEN "I",#1,fn$                       ! Datei zum Lesen öffnen
  161.     id$=INPUT$(4,#1)                      ! Header-ID lesen
  162.     h_l%=CVL(INPUT$(4,#1))                ! Header-Länge lesen
  163.     ff&=CVI(INPUT$(2,#1))                 ! File-Typ lesen
  164.     anz&=CVI(INPUT$(2,#1))                ! Spuranzahl
  165.     res&=CVI(INPUT$(2,#1))                ! Auflösung
  166.     IF id$<>"MThd" OR ff%<>0              ! MIDI-File vom Typ 0?
  167.       ALERT 3,"Ungültiges Fileformat - |Fileheader",1," OK ",r
  168.       GOTO cancel                         ! Nein, dann Abbruch
  169.     ENDIF
  170.     id$=INPUT$(4,#1)                      ! Track-ID lesen
  171.     b_l%=CVL(INPUT$(4,#1))                ! Länge der Spur
  172.     IF id$<>"MTrk"                        ! Track-ID prüfen
  173.       ALERT 3,"Ungültiges Fileformat - |Trackstruktur",1," OK ",r
  174.       GOTO cancel                         ! Ungültig? dann raus
  175.     ENDIF
  176.     DO                                    ! Leseschleife
  177.       INC c%                              ! Zähler für Feld erhöhen
  178.       t$=""
  179.       DO                                  ! Leseschleife für Zeit
  180.         tim$=INPUT$(1,#1)                 ! Erstes Byte lesen
  181.         INC b%                            ! Bytezähler +1
  182.         t$=t$+tim$                        ! ersten Zeitwert bilden
  183.         EXIT IF ASC(tim$)<128             ! raus, wenn LSB gelesen
  184.       LOOP
  185.       VOID FRE(0)
  186.       t$=MID$(t$,1,4)
  187.       t$=STRING$(4-LEN(t$),0)+t$          ! Langwort bilden
  188.       r%=V:r$                             ! Adresse der Maschinenroutine
  189.       POKE r%+2,0                         ! Opcode: 0=VLN-->DEZ
  190.       LPOKE r%+6,CVL(t$)                  ! Wert übergeben
  191.       d0=C:r%()                           ! Maschinenprogramm aufrufen
  192.       IF abs_rel|=0                       ! Relative Zeit benötigt?
  193.         time%(c%)=LPEEK(r%+6)/(res&/24)   ! dann Delta-Time ablegen
  194.       ELSE                                ! Absolutzeit?
  195.         z%=z%+LPEEK(r%+6)                 ! dann Zeit bilden...
  196.         time%(c%)=z%/(res&/24)            ! ...und in interne Auflösung umrechnen
  197.       ENDIF
  198.       evt$=INPUT$(1,#1)                   ! Event, erstes Byte lesen
  199.       INC b%                              ! wieder ein Byte mehr...
  200.       rb|=(ASC(evt$)) AND &HF0            ! nur Hi-Nibble wird benötigt
  201.       IF d_len&(rb|)=0                    ! Event-Typ ist nicht bekannt?
  202.         ALERT 3,"ERROR:|Unbekanntes MIDI-Event",1,"CANCEL",r
  203.         EXIT IF r=1                       ! dann nix wie raus...
  204.       ENDIF
  205.       IF evt$=CHR$(&HFF)                  ! Event ist Meta-Event...
  206.         m_type&=ASC(INPUT$(1,#1))         ! ...dann Event-Typ feststellen
  207.         m_l&=ASC(INPUT$(1,#1))            ! Länge feststellen
  208.         RELSEEK #1,m_l&                   ! Meta-Event ignorieren...
  209.         b%=b%+m_l&+2                      ! ...und überspringen
  210.         EXIT IF m_type&=&H2F              ! raus wenn Meta-Event = Spurende
  211.       ELSE
  212.         dat$(c%)=evt$+INPUT$(d_len&(rb|)-1,#1) ! wenn normales MIDI-Event...
  213.         b%=b%+d_len&(rb|)                 ! ... dann lesen und speichern
  214.       ENDIF
  215.     LOOP
  216.     last%=c%                              ! Spurende
  217.   ENDIF
  218. cancel:
  219.   CLOSE #1                                ! Datei schließen
  220.   DEFMOUSE 0                              ! Biene wegzaubern
  221. RETURN
  222. '
  223. PROCEDURE convert_init
  224.   '
  225.   ' Initialisierung der VLN/Dezimal-Routine.
  226.   ' Die in r$ abgelegte Maschinenroutine erwartet in V:r$+2 als Byte den
  227.   ' Opcode der auszuführenden Berechnung (0=VLN in Dezimalwert umrechnen,
  228.   ' 1=Dezimalwert in VLN umrechnen) und in V:r$+6 den umzurechnenden Wert.
  229.   ' Nach Aufruf der Routine kann von dort auch der berechnete Wert gelesen
  230.   ' werden (Langwort). Die Wertübergabe über die Speicherstelle habe ich
  231.   ' gewählt, weil die Übergabe über den Stack bei meiner GFA-Version nicht
  232.   ' korrekt funktioniert.
  233.   '
  234.   r$=MKL$(&H60080000)+MKL$(0)+MKL$(&H41FA)+MKL$(&HFFF62228)
  235.   r$=r$+MKL$(&H44A10)+MKL$(&H6754B2BC)+MKL$(&HFFFFFFF)+MKL$(&H62407003)
  236.   r$=r$+MKL$(&HE389E209)+MKL$(&H8810007)+MKL$(&HB07C0003)+MKL$(&H67084A01)
  237.   r$=r$+MKL$(&H670408C1)+MKL$(&H71401)+MKL$(&HE09AE089)+MKL$(&H51C8FFE2)
  238.   r$=r$+MKL$(&H8020017)+MKL$(&H670408C2)+MKL$(&HF0802)+MKL$(&H1F6706)
  239.   r$=r$+MKL$(&H820080)+MKL$(&H80002142)+MKL$(&H47000)+MKL$(&H4E75217C)
  240.   r$=r$+MKL$(&HFFFFFFF7)+MKL$(&H470FF)+MKL$(&H4E75B2BC)+MKL$(&HFFFFFFF7)
  241.   r$=r$+MKL$(&H62167003)+MKL$(&H1401EE9A)+MKL$(&HE08951C8)+MKL$(&HFFF8E89A)
  242.   r$=r$+MKL$(&H2820FFF)+MKL$(&HFFFF60CE)+MKL$(&H217C0FFF)+MKL$(&HFFFF0004)
  243.   r$=r$+MKL$(&H70FF4E75)
  244.   '
  245.   '
  246.   d_len&(128)=3                         ! Note-Off,Befehlslänge 3 Bytes
  247.   d_len&(144)=3                         ! Note-On, Befehlslänge 3 Bytes
  248.   d_len&(160)=3                         ! Poly Pressure
  249.   d_len&(176)=3                         ! Control Change
  250.   d_len&(192)=2                         ! Program Change
  251.   d_len&(208)=2                         ! Channel Pressure
  252.   d_len&(224)=3                         ! Pitch Wheel Change
  253.   d_len&(&HF0)=&HFF                     ! Meta-Event darf keinen Fehler erzeugen
  254.   '
  255.   ' Es können hier weitere Befehlslängen für MIDI-Nachrichten eingetragen werden
  256.   '
  257. RETURN
  258. '
  259. PROCEDURE all_notes_off
  260.   FOR chan|=0 TO 15             ! Alle Kanäle durchgehen...
  261.     FOR note|=0 TO 127          ! Alle Noten durchgehen...
  262.       IF note|=0                ! Erstes Note-Off normal..
  263.         OUT 3,128+chan|
  264.       ENDIF
  265.       OUT 3,note|,0             ! ..den Rest im Running-Mode
  266.     NEXT note|                  ! senden (geht schneller)
  267.   NEXT chan|
  268. RETURN
  269.